package gsw.common.webView;

import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslError;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.ViewGroup;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import gsw.common.R;

/**
 * WebView的demo
 * 在Android上调试WebView，使用Stetho
 * <p>
 * 参考：https://blog.csdn.net/carson_ho/article/details/52693322
 */
public class ActivityWebView extends AppCompatActivity {

    String url = "https://www.jianshu.com/p/8e8aeeb2fbf8";
    //String url = "http://10.180.186.20:1111/#/";
    WebView webView = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);

        initWebView();
    }

    /**
     * 初始化Webview
     */
    private void initWebView() {
        getWebView();
        initWebSettings();
        loadUrl(url);
        initWebViewClient();
        initWebChromeClient();
    }

    /**
     * 生成Webview
     */
    private void getWebView() {
        //方式1：直接在在Activity中生成。推荐使用方式1，可以避免内存泄漏。
        webView = new WebView(this);
        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        addContentView(webView, layoutParams);

        //方法2：在Activity的layout文件里添加webview控件：
        //webView = findViewById(R.id.webView_xml);
    }

    /**
     * 初始化WebSettings
     * 用于管理WebView状态配置，当WebView第一次被创建时，WebView包含着一个默认的配置，这些默认的配置将通过get方法返回，
     * 通过WebView中的getSettings方法获得一个WebSettings对象，如果一个WebView被销毁，在WebSettings中所有回调方法将抛出IllegalStateException异常。
     */
    private void initWebSettings() {
        //声明WebSettings子类
        WebSettings webSettings = webView.getSettings();

        //如果访问的页面中要与Javascript交互，则webview必须设置支持Javascript
        webSettings.setJavaScriptEnabled(true);

        //设置自适应屏幕，两者合用
        webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
        webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小

        //缩放操作
        webSettings.setSupportZoom(true); //支持缩放，默认为true。是下面那个的前提。
        webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false，则该WebView不可缩放
        webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件

        //其他细节操作
        webSettings.setAllowFileAccess(true); //设置可以访问文件
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
        webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
        webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式

        //设置缓存
        setWebViewCache(webSettings);
    }

    /**
     * 设置缓存
     */
    private void setWebViewCache(WebSettings webSettings) {
        //设置缓存。
        //当加载html页面时，WebView会在/data/data/包名目录下生成app_webview与cache两个文件夹,
        //app_webview包含cookies和WebData,其中WebData缓存请求的url记录；cache包含缓存的js、css、图片等资源。
        //缓存模式如下：
        //LOAD_CACHE_ONLY: 不使用网络，只读取本地缓存数据
        //LOAD_DEFAULT: （默认）根据cache-control决定是否从网络上取数据。
        //LOAD_NO_CACHE: 不使用缓存，只从网络获取数据.
        //LOAD_CACHE_ELSE_NETWORK: 只要本地有，无论是否过期、后台是否支持，都使用缓存中的数据。
        webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);

        /**
         * AppCache是对Cache的补充，用来指定缓存策略。
         * 开启AppCache，需要先开启Cache，并且设置AppCachePath。
         * 开启AppCache，需要在Html中指定manifest，manifest中指定可以离线缓存的文件。
         * 第一次打开H5时，会缓存manifest中指定的文件。当manifest文件变化时，会自动更新缓存。
         * 但是，manifest中指定的文件内容变化时，并不会更新缓存，需要通过 window.applicationCache.update()手动更新。
         */
        webSettings.setAppCacheEnabled(true);
        webSettings.setAppCachePath(getFilesDir().getAbsolutePath() + "/cache_webView");

        /**
         * 开启文件存储
         */
        //开启DomStorage，使H5的LocalStorage和SessionStorage生效
        webSettings.setDomStorageEnabled(true);
        //开启Database，使H5的IndexedDB和WebSQL生效
        webSettings.setDatabaseEnabled(true);
    }

    /**
     * 加载网页
     *
     * @param url 网页地址
     */
    public void loadUrl(String url) {
        webView.loadUrl(url);

        /**
         * 方式1. 加载一个网页：
         */
        //webView.loadUrl("http://www.google.com/");

        /**
         *  方式2：加载apk包中的Html页面
         *  Html文件位于位于assets下，url格式为"file:///android_asset/+文件路径"
         */
        //webView.loadUrl("file:///android_asset/test.html");

        /**
         * 方式3：加载手机本地的html页面
         * Html文件位于位于SD卡中，url格式为"content://com.android.htmlfileprovider/sdcard/+文件路径"
         */
        //webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
    }

    /**
     * 初始化WebViewClient
     * 作用：处理各种通知、请求事件
     */
    public void initWebViewClient() {
        WebViewClient webViewClient = new WebViewClient() {

            /**
             * 打开网页时，会自动调用这个方法。
             * 指定http协议的url用webView打开，非http协议的url由安卓系统打开。
             */
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (url.startsWith("http:")) {
                    view.loadUrl(url);
                } else {
                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                    try {
                        startActivity(intent);
                    } catch (Exception e) {

                    }
                }
                return true;
            }

            /**
             * 开始载入页面调用的，我们可以设定一个loading的页面，告诉用户程序在等待网络响应。
             */
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                //设定加载开始的操作
            }

            /**
             * 在页面加载结束时调用。我们可以关闭loading 条，切换程序动作。
             */
            @Override
            public void onPageFinished(WebView view, String url) {
                //设定加载结束的操作
            }

            /**
             * 在加载页面资源时会调用，每一个资源（比如图片）的加载都会调用一次。
             */
            @Override
            public void onLoadResource(WebView view, String url) {
                //设定加载资源的操作
            }

            /**
             * 加载页面的服务器出现错误时（如404）调用。
             */
            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                //加载出错时，可以加载本地页面
            }

            /**
             * 处理https请求
             * webView默认是不处理https请求的，页面显示空白，需要进行如下设置：
             */
            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                //表示等待证书响应
                handler.proceed();
                //表示挂起连接，为默认方式
                //handler.cancel();
                //可做其他处理
                //handler.handleMessage(null);
            }
        };
        webView.setWebViewClient(webViewClient);

    }

    /**
     * 初始化WebChromeClient
     * 作用：辅助WebView处理Javascript的对话框,网站图标,网站标题等等
     */
    public void initWebChromeClient() {
        WebChromeClient webChromeClient = new WebChromeClient() {

            /**
             * 获得网页的加载进度并显示
             */
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                String progress = newProgress + "%";
            }


            /**
             * 获取Web页中的标题
             */
            @Override
            public void onReceivedTitle(WebView view, String title) {
            }
        };

        webView.setWebChromeClient(webChromeClient);
    }

    /**
     * 清除WebView缓存
     */
    public void clearCache() {
        //清除网页访问留下的缓存
        //由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
        webView.clearCache(true);

        //清除当前webview访问的历史记录
        //只会webview访问历史记录里的所有记录除了当前访问记录
        webView.clearHistory();

        //这个api仅仅清除自动完成填充的表单数据，并不会清除WebView存储到本地的数据
        webView.clearFormData();
    }

    /**
     * WebView的前进与后退
     * <p>
     * //是否可以后退
     * webView.canGoBack();
     * //后退网页
     * webView.goBack();
     * <p>
     * //是否可以前进
     * webView.canGoForward();
     * //前进网页
     * webView.goForward();
     * <p>
     * //以当前的index为起始点前进或者后退到历史记录中指定的steps
     * //如果steps为负数则为后退，正数则为前进
     * webView.goBackOrForward(-1);
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webView != null && webView.canGoBack()) {
            webView.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    /**
     * WebView的状态
     * <p>
     * //激活WebView为活跃状态，能正常执行网页的响应
     * webView.onResume();
     * <p>
     * //当应用程序(存在webview)被切换到后台时，这个方法不仅仅针对当前的webview而是全局的全应用程序的webview
     * //它会暂停所有webview的layout，parsing，javascripttimer。降低CPU功耗。
     * webView.pauseTimers();
     * //恢复pauseTimers状态
     * webView.resumeTimers();
     * <p>
     * //当页面被失去焦点被切换到后台不可见状态，需要执行onPause
     * //通过onPause动作通知内核暂停所有的动作，比如DOM的解析、plugin的执行、JavaScript执行。
     * webView.onPause();
     * <p>
     * //销毁Webview
     * //在关闭了Activity时，如果Webview的音乐或视频，还在播放。就必须销毁Webview
     * //但是注意：webview调用destory时,webview仍绑定在Activity上
     * //这是由于自定义webview构建时传入了该Activity的context对象
     * //因此需要先从父容器中移除webview,然后再销毁webview:
     * ((ViewGroup) webView.getParent()).removeView(webView);
     * webView.destroy();
     */
    @Override
    protected void onResume() {
        super.onResume();
        if (webView != null) {
            webView.onResume();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (webView != null) {
            webView.onPause();
        }
    }

    /**
     * 避免WebView内存泄露:
     * 1.不在xml中定义Webview，而是在需要的时候在Activity中创建，并且Context使用getApplicationgContext();
     * 2.在Activity销毁WebView的时候，先让WebView加载null内容，然后移除 WebView，再销毁WebView，最后置空。
     */
    @Override
    protected void onDestroy() {
        if (webView != null) {
            webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
            webView.clearHistory();

            ((ViewGroup) webView.getParent()).removeView(webView);
            webView.destroy();
            webView = null;
        }
        super.onDestroy();
    }

}
